_ENV.import("./Element/init.lua");
_ENV.import("./KeyBoard.lua");
_ENV.import("./Event.lua");

local Window = _ENV.import("./Window.lua");

local WindowList = {};            -- 窗口列表 zorder 由小到大排列
local WindowMap = {};             -- 窗口集
local WindowWidth, WindowHeight = commonlib.GetWindowWidth(), commonlib.GetWindowHeight();
local MouseX, MouseY = 0, 0;      -- 鼠标位置
local MouseCaptureWindow = nil;   -- 鼠标捕获窗口
local ActiveWindow = nil;         -- 当前激活窗口

-- 添加窗口至窗口列表
local function AddWindowToWindowList(target_window)
    local zorder = target_window:GetZOrder();
    local exist = false;
    local index, pos = 1, nil;
    local windows = {};
    for _, win in ipairs(WindowList) do
        if (not win:IsDestroy()) then
            if (win == target_window) then exist = true end

            if (pos == nil and zorder < win:GetZOrder()) then pos = index end

            table.insert(windows, win);

            index = index + 1;
        end
    end
    if (not exist) then table.insert(windows, pos or index, target_window) end
    WindowList = windows;
end

-- 获取鼠标窗口
local function GetMouseWindow(mouse_x, mouse_y, is_active_window)
    if (MouseCaptureWindow and not MouseCaptureWindow:IsDestroy()) then return MouseCaptureWindow end

    local size = #(WindowList);
    local mouse_window = WindowList[size];

    for i = size, 1, -1 do
        local win = WindowList[i];
        local winX, winY, winW, winH = win:GetWindowPosition();
        if (winX <= mouse_x and mouse_x <= (winX + winW) and winY <= mouse_y and mouse_y <= (winY + winH)) then
            mouse_window = win;
            break;
        end
    end

    if (is_active_window) then ActiveWindow = mouse_window end

    return mouse_window;
end

-- 获取激活窗口
local function GetActiveWindow()
    return ActiveWindow;
end

-- 窗口大小改变事件回调
local function OnWindowSize(width, height)
    WindowWidth, WindowHeight = width, height;
    for _, win in ipairs(WindowList) do
        win:OnSize(WindowWidth, WindowHeight);
    end
end

-- 鼠标按下回调
local function OnMouseDown(x, y, mouse_button)
    MouseX, MouseY  = x, y;
    local win = GetMouseWindow(x, y);
    local event = commonlib.InitMouseEvent(win, "onmousedown", x, y, mouse_button);
    return win and win:OnEvent(event);
end

local function OnMouseMove(x, y)
    MouseX, MouseY  = x, y;
    local win = GetMouseWindow(x, y);
    local event = commonlib.InitMouseEvent(win, "onmousemove", x, y);
    return win and win:OnEvent(event);
end

local function OnMouseUp(x, y, mouse_button)
    MouseX, MouseY  = x, y;
    local win = GetMouseWindow(x, y);
    local event = commonlib.InitMouseEvent(win, "onmouseup", x, y, mouse_button);
    return win and win:OnEvent(event);
end

local function OnMouseWheel(mouse_wheel_x, mouse_wheel_y)
    local win = GetMouseWindow(x, y);
    local event = commonlib.InitMouseEvent(win, "onmousewheel", nil, nil, 0, mouse_wheel_x, mouse_wheel_y);
    return win and win:OnEvent(event);
end

local function OnKeyDown(keycode)
    commonlib.SetKeyPressed(keycode, true);
    local win = GetActiveWindow();
    local event = commonlib.InitKeyEvent(win, "onkeydown", keycode);
    return win and win:OnEvent(event);
end

local function OnKeyUp(keycode)
    commonlib.SetKeyPressed(keycode, false);
    local win = GetActiveWindow();
    local event = commonlib.InitKeyEvent(win, "onkeyup", keycode);
    return win and win:OnEvent(event);
end

local function OnChar(key)
    local win = GetActiveWindow();
    local event = commonlib.InitCharEvent(win, key);
    return win and win:OnEvent(event);
end

-- C++ CallBack
_G.__on_window_size__ = commonlib.xpcall_callback(OnWindowSize);

-- C++ CallBack
_G.__on_mouse_down__ = commonlib.xpcall_callback(OnMouseDown);

-- C++ CallBack
_G.__on_mouse_move__ = commonlib.xpcall_callback(OnMouseMove);

-- C++ CallBack
_G.__on_mouse_up__ = commonlib.xpcall_callback(OnMouseUp);

-- C++ CallBack
_G.__on_mouse_wheel__ = commonlib.xpcall_callback(OnMouseWheel);

-- C++ CallBack
_G.__on_key_down__ = commonlib.xpcall_callback(OnKeyDown);

-- C++ CallBack
_G.__on_key_up__ = commonlib.xpcall_callback(OnKeyUp);

-- C++ CallBack
_G.__on_char__ = commonlib.xpcall_callback(OnChar);


-- 获取主窗口宽高
commonlib.GetWindowWidthHeight = function()
    return WindowWidth, WindowHeight;
end

-- 获取鼠标位置
commonlib.GetMouseXY = function()
    return MouseX, MouseY;
end

-- 创建并显示窗口
commonlib.ShowWindow = function(params)
    local win = Window:new():Init(params);
    local key = win:GetKey();

    if (key) then
        local old_win = WindowMap[key];
        if (old_win) then old_win:Close() end
        WindowMap[key] = win;
    end

    AddWindowToWindowList(win);

    win:Show();

    return win;
end

commonlib.SetActiveWindow = function(win)
    ActiveWindow = win;
end

commonlib.GetActiveWindow = function()
    return ActiveWindow;
end

commonlib.SetMouseCaptureWindow = function(win)
    MouseCaptureWindow = win;
end

commonlib.GetMouseCaptureWindow = function()
    return MouseCaptureWindow;
end

commonlib.SetInterval(0, function()
    local painter = commonlib.GetWindowPainter();
    painter:Clear();
    for _, window in ipairs(WindowList) do
        window:Render();
    end
    painter:Flush();
end);